<!-- 门牌批量编号 -->
<template>
  <div class="">
    <PagePanel :panelTitle="activePanel.panelTitle" @clickClose="clickClose">
      <el-card class="box-card"
        >提示：地图上点击选中道路，查看附近建筑信息、及关联的门牌信息。</el-card
      >
      <el-card style="margin-top: 10px" class="box-card">
        <div slot="header" class="clearfix">
          <span>当前道路信息</span>
        </div>
        道路名称：{{ currentRoad?.properties?.getValue ? currentRoad.properties.getValue().name : '' }}
      </el-card>
      <el-card style="margin-top: 10px" class="box-card">
        <div slot="header" class="clearfix">
          <span>关联门牌信息</span>
        </div>
        <!-- <div v-for="o in 4" :key="o" class="text item">
          {{ "关联门牌信息 " + o }}
        </div> -->
        <el-table :data="buildings" border @cell-dblclick="clickevent">
          <el-table-column v-for="item in tableColumns" :prop="item.prop" :label="item.label" :key="item.id" sortable>
            <template #default="{row,column}">
              <el-input v-model="row[item.prop]"  v-show="row[column.property + 'isShow']" @blur="alterData(row,column)"></el-input>
              <span v-if="column.property === 'doorplate'"  v-show="!row[column.property + 'isShow']">{{ !row.doorplate ? '未编号' : row.doorplate}}</span>
              <span v-else  v-show="!row[column.property + 'isShow']">{{ row[column.property] }}</span>
            </template>
          </el-table-column>
        </el-table>
        <el-button @click="startNumber">自动编号</el-button><el-button @click="save">保存</el-button>
      </el-card>
    </PagePanel>
  </div>
</template>

<script>
import PagePanel from '@/components/PagePanel'
import { findAllBuildings, saveDoorplate } from '@/api/home.js'
import { getAllRoads } from '@/api/road.js'
import * as turf from '@turf/turf'
import turf_intersect from '@turf/intersect'

const Cesium = window.Cesium
const RoadEntityName = 'road'
const BuildingEntityName = 'building'

export default {
  name: 'HouseNumBatchNum',
  components: { PagePanel },
  data () {
    return {
      currentRoad: null,
      currentRoadTurfObj:null,
      roadStartPt: null,
      surroundingBuildings: null,
      tableColumns: [
        { id: '1', prop: 'id', label: '编号' },
        { id: '2', prop: 'name', label: '名称' },
        { id: '3', prop: 'doorplate', label: '门牌' }
      ],
      buildings: []
    }
  },
  computed: {
    activePanel () {
      return this.$store.state.activePanel
    }
  },
  mounted () {
    this.loadGisData()
    this.initGisEvent()
  },
  methods: {
    clickClose () {
      console.log('@@@@@@@@@@@@', this.activePanel)
    },

    clickevent (row, column) {
      if (column.property === 'doorplate') {
        return
      }

      row[column.property + 'isShow'] = true
      this.$nextTick(() => {
        this.$refs[column.property] && this.$refs[column.property].focus()
      })
    },

    alterData (row, column) {
      row[column.property + 'isShow'] = false
      if (column.property === 'doorplate') {
        // this.changeData({ id: row.id, doorplate: row[column.property] })
        this.updateBuildingLabel({ id: row.id, doorplate: row[column.property] })
      }
    },

    loadGisData () {
      // 道路
      this.loadRoad()
      // 建筑
      this.loadBuildings()
    },

    initGisEvent () {
      const handler = new Cesium.ScreenSpaceEventHandler(
        window.cesiumViewer.scene.canvas
      )
      handler.setInputAction((event) => {
        const pickedEntity = window.cesiumViewer.scene.pick(event.position)
        console.log(pickedEntity)
        if (pickedEntity?.id?.name === 'road') {
          this.currentRoad = pickedEntity.id

          this.loadRelationalBuilding()
        }
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
    },

    loadRelationalBuilding () {
      const bufferSize = 100// 50
      // 道路
      const linePoints_cartesion = this.currentRoad.polyline.positions.getValue()

      //
      const linePoints = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(linePoints_cartesion)
      const temp = []
      linePoints.map((pt) => {
        const t = [Cesium.Math.toDegrees(pt.longitude), Cesium.Math.toDegrees(pt.latitude)]
        temp.push(t)
      })

      // 判断道路方向 ，x,y 方向差值大小比较
      const dx = temp[temp.length - 1][0] - temp[0][0]
      const dy = temp[temp.length - 1][1] - temp[0][1]
      let lineDir = 1
      let startPoint = temp[0]
      if (Math.abs(dx) > Math.abs(dy) && dx > 0) {
        lineDir = 1
        startPoint = temp[0]
      } else if (Math.abs(dx) > Math.abs(dy) && dx < 0) {
        lineDir = 1
        startPoint = temp[temp.lenth - 1]
      } else if (Math.abs(dx) < Math.abs(dy) && dy < 0) {
        lineDir = 0
        startPoint = temp[0]
      } else if (Math.abs(dx) < Math.abs(dy) && dy > 0) {
        lineDir = 0
        startPoint = temp[temp.length - 1]
      }

      this.roadStartPt = turf.point(startPoint)

      const line = turf.lineString(temp)
      this.currentRoadTurfObj = line

      // 构建缓冲区（50米缓冲区）
      const buffer = turf.buffer(line, bufferSize, { units: 'meters' })

      // [{id,distance,direction}]
      const buildingsResult = []

      const aroundBuilding = []
      // 获取道路周边的建筑
      this.gisdata_building.map(building => {
        const polygon = building.properties.getValue().positions
        const ptArr = polygon.split(',')
        const temp = []
        for (let i = 0; i < ptArr.length; i += 2) {
          temp.push([Number(ptArr[i]), Number(ptArr[i + 1])])
        }
        if (temp[0] !== temp[temp.length - 1]) {
          temp.push(temp[0])
        }
        const geoPolygon = turf.polygon([temp])
        // const cross = turf.booleanCrosses(geoPolygon, buffer)
        console.log(geoPolygon, buffer)
        const cross = turf_intersect(geoPolygon, buffer)
        if (cross) {
          aroundBuilding.push(building)
        }
      })
      this.surroundingBuildings = aroundBuilding
      this.setTableData(aroundBuilding.map(entity => {return entity.properties.getValue()}))
    },

    startNumber () {
      // this.calculateDistance(this.currentRoad)

      // [{id,distance,direction,name,doorplate}]
      const buildingsResult = []
      // 计算建筑到道路的距离及方向
      this.surroundingBuildings.map((building) => {
        const buildid = building.properties.getValue().id
        const buildName = building.properties.getValue().name
        // const buildingPoints =
        // 建筑中心点
        const buildingCenter = this.getCenter(building)
        // 建筑到道路的距离
        const distanceL = turf.pointToLineDistance(buildingCenter, this.currentRoadTurfObj, {
          units: 'meters'
        })
        // 建筑到道路起点的距离
        const distance = turf.rhumbDistance(buildingCenter, this.roadStartPt, { units: 'meters' })
        console.log('距离：', distance)
        // var pt = turf.point([0, 0]);
        // var line = turf.lineString([[1, 1],[-1, 1]]);

        // 道路
      const linePoints_cartesion = this.currentRoad.polyline.positions.getValue()
      const linePoints = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(linePoints_cartesion)
      const temp = []
      linePoints.map((pt) => {
        const t = [Cesium.Math.toDegrees(pt.longitude), Cesium.Math.toDegrees(pt.latitude)]
        temp.push(t)
      })
        const line2 = turf.lineString([
          buildingCenter.geometry.coordinates,
          ...temp,
          buildingCenter.geometry.coordinates
        ])

        // 逆时针 false 右侧 顺时针 true 左侧
        const dir = turf.booleanClockwise(line2)
        if (dir) {
          // 左
          console.log('左')
        } else {
          // 右
          console.log('右')
        }
        // 左单右双 从上到下
        buildingsResult.push({ id: buildid, distance, direction: dir, name: buildName })
      })

      // FID 作为主键
      // })

      // 排序
      // buildingsResult.sort(this.compareValues('distance'));
      // 多重排序
      buildingsResult.sort(this.compareTwoValues(['direction', 'distance']))

      let indexSingular = -1
      let indexDual = 0
      // dir true(顺时针)，为左， dirfalse 为右；左单右双
      buildingsResult.map(b => {
        if (b.direction) {
          b.doorplate = (indexSingular += 2)
        } else {
          b.doorplate = (indexDual += 2)
        }
      })

      // 更新label

      this.setTableData(buildingsResult)
      console.log(buildingsResult)
    },

    loadRoad () {
      getAllRoads().then(response => {
        const data = JSON.parse(response.data)
        const entities = []
        data.map(road => {
          const pts = road.lines.split(',')
          const entity = window.cesiumViewer.entities.add({
            name: 'line',
            polyline: {
              positions: Cesium.Cartesian3.fromDegreesArray(pts),
              width: 10,
              arcType: Cesium.ArcType.RHUMB,
              material: Cesium.Color.GREEN
            },
            properties: road
          })
          entities.push(entity)
        })

        entities.map((entity) => {
          entity.name = RoadEntityName
        })

        window.cesiumViewer.flyTo(entities)
      })
    },

    loadBuildings () {
      findAllBuildings().then(result => {
        const buildings = JSON.parse(result.data)

        const buildingEntities = []
        buildings.map(build => {
          const positions = build.positions.split(',')
          // const center_cartocraphic = this.getCenterByXYArr(positions)
          const entity = window.cesiumViewer.entities.add({
            id: 'building_' + build.id,
            polygon: {
              hierarchy: Cesium.Cartesian3.fromDegreesArray(positions),
              material: Cesium.Color.YELLOW.withAlpha(0.5),
              outline: true,
              outlineWidth:1,
              outlineColor: Cesium.Color.BLUE,
            },
            properties: build,
            // label: {
            //   fillColor: Cesium.Color.LIGHTBLUE,
            //   text: build.doorplate ? build.doorplate : "未编号",
            //   font: '20px sans-serif',
            //   pixelOffset: new Cesium.Cartesian2(0.0, -30),
            //   disableDepthTestDistance: Number.POSITIVE_INFINITY // 去掉地形遮挡
            // }
          })
          buildingEntities.push(entity)
        })
        buildingEntities.map((entity) => {
          entity.name = BuildingEntityName
        })
        this.gisdata_building = buildingEntities

        // 显示建筑注记
        this.displayBuildingLabel()
      })
    },

    displayBuildingLabel () {
      this.gisdata_building.map((entity) => {
        const center_cartocraphic = this.getCenter(entity)
        const center_cartesion = Cesium.Cartesian3.fromRadians(
          center_cartocraphic.geometry.coordinates[0],
          center_cartocraphic.geometry.coordinates[1],
          0
        )
        var polyPositions = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions;
        var polyCenter = Cesium.BoundingSphere.fromPoints(polyPositions).center;//中心点
        polyCenter = Cesium.Ellipsoid.WGS84.scaleToGeodeticSurface(polyCenter);
        entity.position = polyCenter;

        // entity.position = center_cartesion
        const properties = entity.properties.getValue();
        const name = properties.name;
        const mph = properties.doorplate
        const text = name + '\n' + ((mph && mph !== '') ? mph : '待编号')
        entity.label = {
          show: true,
          text: text,
          font: '8px sans-serif',
          color: Cesium.Color.YELLOWGREEN,
          fillColor: Cesium.Color.YELLOWGREEN,
          style: Cesium.LabelStyle.FILL_AND_OUTLINE,
          showBackground: true,
          backgroundColor: Cesium.Color(255, 255, 0),
          scaleByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 1.5e7, 0.5),
          translucencyByDistance: new Cesium.NearFarScalar(
            1.5e2,
            1.0,
            1.5e8,
            0.0
          ),
          verticalOrigin: Cesium.VerticalOrigin.LEFT,
          pixelOffset: new Cesium.Cartesian2(0.0, -12.0)
        }
      })
    },

    // 修改表格中门牌信息时更新到地图注记
    updateBuildingLabel (data) {
      const entity = window.cesiumViewer.entities.getById('building_' + data.id)
      if (entity) {
        entity.label.text = data.doorplate
      }
    },

    /**
     * 计算道路附近建筑距离
     * 计算方向，线和点连接，然后判断是顺时针或逆时针确定方向
     * @param {*} entity 道路实体
     */
    calculateDistance (entity) {
      const bufferSize = 100// 50
      // 道路
      const linePoints_cartesion = entity.polyline.positions.getValue()

      //
      const linePoints = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(linePoints_cartesion)
      const temp = []
      linePoints.map((pt) => {
        const t = [Cesium.Math.toDegrees(pt.longitude), Cesium.Math.toDegrees(pt.latitude)]
        temp.push(t)
      })

      // 判断道路方向 ，x,y 方向差值大小比较
      const dx = temp[temp.length - 1][0] - temp[0][0]
      const dy = temp[temp.length - 1][1] - temp[0][1]
      let lineDir = 1
      let startPoint = temp[0]
      if (Math.abs(dx) > Math.abs(dy) && dx > 0) {
        lineDir = 1
        startPoint = temp[0]
      } else if (Math.abs(dx) > Math.abs(dy) && dx < 0) {
        lineDir = 1
        startPoint = temp[temp.lenth - 1]
      } else if (Math.abs(dx) < Math.abs(dy) && dy < 0) {
        lineDir = 0
        startPoint = temp[0]
      } else if (Math.abs(dx) < Math.abs(dy) && dy > 0) {
        lineDir = 0
        startPoint = temp[temp.length - 1]
      }

      const roadStartPt = turf.point(startPoint)

      const line = turf.lineString(temp)

      // 构建缓冲区（50米缓冲区）
      const buffer = turf.buffer(line, bufferSize, { units: 'meters' })

      // [{id,distance,direction}]
      const buildingsResult = []

      const aroundBuilding = []
      // 获取道路周边的建筑
      this.gisdata_building.map(building => {
        const polygon = building.properties.getValue().positions
        const ptArr = polygon.split(',')
        const temp = []
        for (let i = 0; i < ptArr.length; i += 2) {
          temp.push([Number(ptArr[i]), Number(ptArr[i + 1])])
        }
        if (temp[0] !== temp[temp.length - 1]) {
          temp.push(temp[0])
        }
        const geoPolygon = turf.polygon([temp])
        // const cross = turf.booleanCrosses(geoPolygon, buffer)
        console.log(geoPolygon, buffer)
        const cross = turf_intersect(geoPolygon, buffer)
        if (cross) {
          aroundBuilding.push(building)
        }
      })

      // 计算建筑到道路的距离及方向
      aroundBuilding.map((building) => {
        const buildid = building.properties.getValue().id
        const buildName = building.properties.getValue().name
        // const buildingPoints =
        // 建筑中心点
        const buildingCenter = this.getCenter(building)
        // 建筑到道路的距离
        const distanceL = turf.pointToLineDistance(buildingCenter, line, {
          units: 'meters'
        })
        // 建筑到道路起点的距离
        const distance = turf.rhumbDistance(buildingCenter, roadStartPt, { units: 'meters' })
        console.log('距离：', distance)
        // var pt = turf.point([0, 0]);
        // var line = turf.lineString([[1, 1],[-1, 1]]);

        const line2 = turf.lineString([
          buildingCenter.geometry.coordinates,
          ...temp,
          buildingCenter.geometry.coordinates
        ])

        // 逆时针 false 右侧 顺时针 true 左侧
        const dir = turf.booleanClockwise(line2)
        if (dir) {
          // 左
          console.log('左')
        } else {
          // 右
          console.log('右')
        }
        // 左单右双 从上到下
        buildingsResult.push({ id: buildid, distance, direction: dir, name: buildName })
      })

      // FID 作为主键
      // })

      // 排序
      // buildingsResult.sort(this.compareValues('distance'));
      // 多重排序
      buildingsResult.sort(this.compareTwoValues(['direction', 'distance']))

      let indexSingular = -1
      let indexDual = 0
      // dir true(顺时针)，为左， dirfalse 为右；左单右双
      buildingsResult.map(b => {
        if (b.direction) {
          b.doorplate = (indexSingular += 2)
        } else {
          b.doorplate = (indexDual += 2)
        }
      })

      // 更新label

      this.setTableData(buildingsResult)
      console.log(buildingsResult)
    },

    /**
     * 获取中点
     * @param {Entity}
     */
    getCenter (entity) {
      const positions_cartesion = entity.polygon.hierarchy.getValue().positions
      const positions =
        Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(
          positions_cartesion
        )
      const pts = []
      positions.map((pt) => {
        pts.push(turf.point([Cesium.Math.toDegrees(pt.longitude), Cesium.Math.toDegrees(pt.latitude)]))
      })
      const features = turf.featureCollection(pts)
      const center = turf.center(features)
      return center
    },

    /**
     * @param positions [x,y,x,y...]
     */
    getCenterByXYArr(xyarr) {
      const positions_cartesion = Cesium.Cartesian3.fromDegreesArray(xyarr);
      const positions =
        Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(
          positions_cartesion
        )
      const pts = []
      positions.map((pt) => {
        pts.push(turf.point([Cesium.Math.toDegrees(pt.longitude), Cesium.Math.toDegrees(pt.latitude)]))
      })
      const features = turf.featureCollection(pts)
      const center = turf.center(features)
      return center
    },

    /**
     * 排序
     * @param key 排序的字段
     * @param order asc/desc
     */
    compareValues (key, order = 'asc') {
      return function innerSort (a, b) {
        if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
          // 该属性在任何一个对象上都不存在
          return 0
        }

        const varA = typeof a[key] === 'string' ? a[key].toUpperCase() : a[key]
        const varB = typeof b[key] === 'string' ? b[key].toUpperCase() : b[key]

        let comparison = 0
        if (varA > varB) {
          comparison = 1
        } else if (varA < varB) {
          comparison = -1
        }
        return order === 'desc' ? comparison * -1 : comparison
      }
    },
    /**
     * 多重排序(2个属性排序)
     * @param {*} key 第一个属性
     * @param {*} key2 第二个属性
     * @param {*} order 升序、降序
     */
    compareTwoValues (key, key2, order = 'asc') {
      return function innerSort (a, b) {
        if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key) || !a.hasOwnProperty(key2) || !b.hasOwnProperty(key2)) {
          // 该属性在任何一个对象上都不存在
          return 0
        }

        const varA = typeof a[key] === 'string' ? a[key].toUpperCase() : a[key]
        const varB = typeof b[key] === 'string' ? b[key].toUpperCase() : b[key]

        let comparison = 0
        if (varA > varB) {
          comparison = 1
        } else if (varA < varB) {
          comparison = -1
        } else if (varA === varB) {
          if (a[key2] > b[key2]) {
            comparison = 1
          } else {
            comparison = -1
          }
        }
        return order === 'desc' ? comparison * -1 : comparison
      }
    },

    setTableData (data) {
      this.buildings = data
    },

    save () {
      this.$confirm('此操作将对门牌号重新编号, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          const doorplates = this.buildings
          saveDoorplate(doorplates).then(result => {
            console.log('save...')
            this.$message({
              type: 'success',
              message: '编号成功!'
            });
          })
          
        }).catch(() => {
          this.$message({
            type: 'info',
            message: '已取消删除'
          });          
        });
    }

    // changeData (data) {
    //   this.$emit('changeDoorPlate', data)
    // }
  },
  beforeDestroy () {
    console.log('切换功能模块');
    // 因为面板都是用的v-if，会销毁面板，需要销毁的事件也可以写这里
    // 移除数据
    window.cesiumViewer.entities.values.map(entity => {
      if (entity.name === BuildingEntityName || entity.name === RoadEntityName) {
        window.cesiumViewer.entities.remove(entity)
      }
    })
  }
}
</script>
<style lang="less" scoped></style>
